import pyautogui
import time
import xlrd
import pyperclip
import tkinter as tk
from threading import Thread
import ctypes
import inspect
import asyncio


def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    try:
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
        if res == 0:
            # pass
            raise ValueError("invalid thread id")
        elif res != 1:
            # """if it returns a number greater than one, you're in trouble,
            # and you should call it again with exc=NULL to revert the effect"""
            ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
            raise SystemError("PyThreadState_SetAsyncExc failed")
    except Exception as err:
        print(err)


def stop_thread(thread):
    """终止线程"""
    _async_raise(thread.ident, SystemExit)



window = tk.Tk()
window.title("窗口")
window.geometry('400x300')
show = "这儿将显示执行状态"
state = tk.StringVar()

def mouseClick(clickTimes, lOrR, img, reTry):
    global show, state
    if reTry == 1:
        while True:
            location = pyautogui.locateCenterOnScreen(img, confidence=0.9)
            if location is not None:
                pyautogui.click(location.x, location.y, clicks=clickTimes, interval=0.2, duration=0.2, button=lOrR)
                break
            print("未找到匹配图片,0.1秒后重试")
            show = "未找到匹配图片,0.1秒后重试"
            state.set(show)
            time.sleep(0.1)
    elif reTry == -1:
        while True:
            location = pyautogui.locateCenterOnScreen(img, confidence=0.9)
            if location is not None:
                pyautogui.click(location.x, location.y, clicks=clickTimes, interval=0.2, duration=0.2, button=lOrR)
            time.sleep(0.1)
    elif reTry > 1:
        i = 1
        while i < reTry + 1:
            location = pyautogui.locateCenterOnScreen(img, confidence=0.9)
            if location is not None:
                pyautogui.click(location.x, location.y, clicks=clickTimes, interval=0.2, duration=0.2, button=lOrR)
                print("重复")
                show = "重复"
                state.set(show)
                i += 1
            time.sleep(0.1)


# 数据检查
# cmdType.value  1.0 左键单击    2.0 左键双击  3.0 右键单击  4.0 输入  5.0 等待  6.0 滚轮
# ctype     空：0
#           字符串：1
#           数字：2
#           日期：3
#           布尔：4
#           error：5
def dataCheck(sheet1):
    global show,state
    checkCmd = True
    # 行数检查
    if sheet1.nrows < 2:
        print("没数据啊哥")
        show = "没数据啊哥"
        state.set(show)
        checkCmd = False
    # 每行数据检查
    i = 1
    while i < sheet1.nrows:
        # 第1列 操作类型检查
        cmdType = sheet1.row(i)[0]
        if cmdType.ctype != 2 or (cmdType.value != 1.0 and cmdType.value != 2.0 and cmdType.value != 3.0
                                  and cmdType.value != 4.0 and cmdType.value != 5.0 and cmdType.value != 6.0):
            print('第', i + 1, "行,第1列数据有毛病")
            show = '第'+str((i+1))+"行,第1列数据有毛病"
            state.set(show)
            checkCmd = False
        # 第2列 内容检查
        cmdValue = sheet1.row(i)[1]
        # 读图点击类型指令，内容必须为字符串类型
        if cmdType.value == 1.0 or cmdType.value == 2.0 or cmdType.value == 3.0:
            if cmdValue.ctype != 1:
                print('第', i + 1, "行,第2列数据有毛病")
                show = '第' + str((i + 1)) + "行,第2列数据有毛病"
                state.set(show)
                checkCmd = False
        # 输入类型，内容不能为空
        if cmdType.value == 4.0:
            if cmdValue.ctype == 0:
                print('第', i + 1, "行,第2列数据有毛病")
                show = '第' + str((i + 1)) + "行,第2列数据有毛病"
                state.set(show)
                checkCmd = False
        # 等待类型，内容必须为数字
        if cmdType.value == 5.0:
            if cmdValue.ctype != 2:
                print('第', i + 1, "行,第2列数据有毛病")
                show = '第' + str((i + 1)) + "行,第2列数据有毛病"
                state.set(show)
                checkCmd = False
        # 滚轮事件，内容必须为数字
        if cmdType.value == 6.0:
            if cmdValue.ctype != 2:
                print('第', i + 1, "行,第2列数据有毛病")
                show = '第' + str((i + 1)) + "行,第2列数据有毛病"
                state.set(show)
                checkCmd = False
        i += 1
    return checkCmd


# 任务
def mainWork(img):
    global show
    i = 1
    while i < sheet1.nrows:
        # 取本行指令的操作类型
        cmdType = sheet1.row(i)[0]
        if cmdType.value == 1.0:
            # 取图片名称
            img = sheet1.row(i)[1].value
            reTry = 1
            if sheet1.row(i)[2].ctype == 2 and sheet1.row(i)[2].value != 0:
                reTry = sheet1.row(i)[2].value
            mouseClick(1, "left", img, reTry)
            print("单击左键", img)
            show = "单击左键"+img
            state.set(show)
        # 2代表双击左键
        elif cmdType.value == 2.0:
            # 取图片名称
            img = sheet1.row(i)[1].value
            # 取重试次数
            reTry = 1
            if sheet1.row(i)[2].ctype == 2 and sheet1.row(i)[2].value != 0:
                reTry = sheet1.row(i)[2].value
            mouseClick(2, "left", img, reTry)
            print("双击左键", img)
            show = "双击左键" + img
            state.set(show)
        # 3代表右键
        elif cmdType.value == 3.0:
            # 取图片名称
            img = sheet1.row(i)[1].value
            # 取重试次数
            reTry = 1
            if sheet1.row(i)[2].ctype == 2 and sheet1.row(i)[2].value != 0:
                reTry = sheet1.row(i)[2].value
            mouseClick(1, "right", img, reTry)
            print("右键", img)
            show = "右键" + img
            state.set(show)
        # 4代表输入
        elif cmdType.value == 4.0:
            inputValue = sheet1.row(i)[1].value
            pyperclip.copy(inputValue)
            pyautogui.hotkey('ctrl', 'v')
            time.sleep(0.5)
            print("输入:", inputValue)
            show = "输入:"+inputValue
            state.set(show)
        # 5代表等待
        elif cmdType.value == 5.0:
            # 取图片名称
            waitTime = sheet1.row(i)[1].value
            time.sleep(waitTime)
            print("等待", waitTime, "秒")
            show = "等待"+waitTime+"秒"
            state.set(show)
        # 6代表滚轮
        elif cmdType.value == 6.0:
            # 取图片名称
            scroll = sheet1.row(i)[1].value
            pyautogui.scroll(int(scroll))
            print("滚轮滑动", int(scroll), "距离")
            show = "滚轮滑动"+scroll+ "距离"
            state.set(show)
        i += 1




l = tk.Label(window, text='欢迎使用本自定义脚本', bg='green', width=20, height=2)
l.pack()
l2 = tk.Label(window, text='执行结束之前请勿重复点击开始，否则容易导致线程爆炸！！', bg='red', width=100, height=1)
l2.pack()

# if __name__ == '__main__':


file = 'cmd.xls'
# 打开文件
wb = xlrd.open_workbook(filename=file)
# 通过索引获取表格sheet页
sheet1 = wb.sheet_by_index(0)
print('欢迎使用本应用~')
# 数据检查
checkCmd = dataCheck(sheet1)



def doOneTime():
    global state
    if checkCmd:
        # 循环拿出每一行指令
        mainWork(sheet1)
        print("执行成功！")
        state.set("执行成功！")

def doToDie():
    global state
    if checkCmd:
        while True:
            mainWork(sheet1)
            time.sleep(0.1)
            print("等待0.1秒")
            state.set("执行成功！等待0.1秒后继续")


new_thread1 = Thread(target=doOneTime)
new_thread2 = Thread(target=doToDie)

def multi():
    global new_thread1
    new_thread1 = Thread(target=doOneTime)
    new_thread1.start()

def always():
    global new_thread2
    new_thread2 = Thread(target=doToDie)
    new_thread2.start()


def stop():
    global new_thread1, new_thread2
    stop_thread(new_thread1)
    stop_thread(new_thread2)


state.set(show)

btn1 = tk.Button(window, text='执行一次', width=15, height=2, command=multi)
btn1.pack()
btn3 = tk.Button(window, text='执行到死', width=15, height=2, command=always)
btn3.pack()

l1 = tk.Label(window, textvariable=state, bg='green', width=100, height=2)
l1.pack()

btn2 = tk.Button(window, text='强制停止任务线程', width=30, height=2, command=stop)
btn2.pack()

window.mainloop()
window.destroy()
